package com.example.demo.demo.lock;

/**
 * @author: htc
 * @date: Created in 18:51 2018/10/25.
 */
public class ReentrantAndNonReentrantLock {
    /**
     * 可重入锁
     */
    ReentrantLock reentrantLock = new ReentrantLock();

    /**
     * 不可重入锁
     */
    NonReentrantLock nonReentrantLock = new NonReentrantLock();

    public void print() throws InterruptedException {
        reentrantLock.lock();
        doAdd();
        reentrantLock.unlock();
    }
    public void doAdd() throws InterruptedException {
        reentrantLock.lock();
        //do something
        reentrantLock.unlock();
    }
}


/**
 * 可重入锁
 * 所谓可重入，意味着线程可以进入它已经拥有的锁的同步代码块儿。

 我们设计两个线程调用print()方法，第一个线程调用print()方法获取锁，进入lock()方法，由于初始lockedBy是null，所以不会进入while而挂起当前线程，而是是增量lockedCount并记录lockBy为第一个线程。接着第一个线程进入doAdd()方法，由于同一进程，所以不会进入while而挂起，接着增量lockedCount，当第二个线程尝试lock，由于isLocked=true,所以他不会获取该锁，直到第一个线程调用两次unlock()将lockCount递减为0，才将标记为isLocked设置为false

 */
class ReentrantLock {
    private boolean isLock = false;

    public synchronized void lock() throws InterruptedException {
        while (isLock) {
            wait();
        }
        isLock = true;
    }

    public synchronized void unlock(){
        isLock =false;
        notify();
    }
}

/**
 * 不可重入锁
 * 当前线程执行print()方法首先获取lock，接下来执行doAdd()方法就无法执行doAdd()中的逻辑，必须先释放锁。这个例子很好的说明了不可重入锁。
 */
class NonReentrantLock {
    private boolean isLock = false;
    Thread currentThread = null;
    int lockedCount = 0;
    public synchronized void lock() throws InterruptedException {
        Thread thread = Thread.currentThread();
        while (isLock && currentThread != thread){
            wait();
        }
        isLock = true;
        lockedCount ++;
        currentThread = thread;
    }

    public synchronized void unlock(){
        if (Thread.currentThread() ==  this.currentThread){
            lockedCount -- ;
            if (lockedCount == 0){
                isLock = false;
                notify();
            }
        }
    }
}